package com.portal.framework.exception.handler.interceptor;

import java.sql.BatchUpdateException;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.DataException;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessException;
import org.springframework.util.PatternMatchUtils;

import com.portal.framework.exception.AppException;
import com.portal.framework.exception.handler.ContentMsgNestedExceptionHandler;
import com.portal.framework.exception.handler.ExceptionHandler;
import com.portal.framework.exception.handler.MsgExceptionHandler;
import com.portal.framework.exception.handler.ResourceExceptionHandler;
import com.portal.framework.util.CollectionUtils;
import com.portal.framework.util.SimplePropertiesSource;

/**
 * 异常处理拦截器<BR>
 * 作用是把方法调用后的exception
 * 
 * @author 卢烁波
 * @date 2007-3-10
 */
public class ExceptionHandleInterceptor implements MethodInterceptor {
	private static final Log log = LogFactory
			.getLog(ExceptionHandleInterceptor.class);

	private List<ExceptionHandler> handlers;
	private Resource[] resources;
	private String[] methodNames;

	public Resource[] getResources() {
		return resources;
	}

	public void setResources(Resource[] resources) {
		this.resources = resources;
	}

	public void setMethodNames(String[] methodNames) {
		this.methodNames = methodNames;
	}

	/**
	 * 如果没有注入将进行默认信息的初始化
	 */
	private void init() {
		handlers = new ArrayList<ExceptionHandler>();

		/**
		 * 根据错误信息处理
		 */
		handlers.add(new ContentMsgNestedExceptionHandler(SQLException.class,"ORA-00001", "主键重复"));
		handlers.add(new ContentMsgNestedExceptionHandler(SQLException.class,"ORA-00942", "表或视图不存在"));
		handlers.add(new ContentMsgNestedExceptionHandler(SQLException.class,"ORA-02292", "有记录被引用"));
		handlers.add(new ContentMsgNestedExceptionHandler(SQLException.class,"ORA-01438", "超出数据库允许存储的最大字段长度"));
		handlers.add(new ContentMsgNestedExceptionHandler(SQLException.class,"ORA-01400", "插入空值错误"));

		/**
		 * 设置字符信息处理
		 */
		handlers.add(new MsgExceptionHandler(ConstraintViolationException.class, "数据库约束错误"));
		handlers.add(new MsgExceptionHandler(DataAccessException.class, "数据库错误"));
		handlers.add(new MsgExceptionHandler(DataException.class, "数据库错误"));
		handlers.add(new MsgExceptionHandler(JDBCException.class, "数据库错误"));
		handlers.add(new MsgExceptionHandler(SQLException.class, "数据库错误"));
		handlers.add(new MsgExceptionHandler(HibernateException.class,
				"Hibernate错误"));

		/**
		 * 设置资源异常信息处理
		 */
		SimplePropertiesSource ps = new SimplePropertiesSource();
		ps.setResources(resources);
		handlers.add(new ResourceExceptionHandler(AppException.class, ps));

		/**
		 * 默认异常处理
		 */
		handlers
				.add(new MsgExceptionHandler(RuntimeException.class, "运行时系统错误"));
		handlers.add(new MsgExceptionHandler(Exception.class, "系统错误"));
	}

	public Object invoke(MethodInvocation inv) throws Throwable {
		if (isMatch(inv.getMethod().getName()) == false) {
			return inv.proceed();
		}

		if (log.isDebugEnabled()) {
			String msg = "进入异常处理拦截器.类名=[{0}],方法名=[{1}]";
			log.debug(MessageFormat.format(msg, inv.getThis().getClass()
					.getName(), inv.getMethod().getName()));
		}
		Object ret = null;
		try {
			ret = inv.proceed();
		} catch (Throwable e) {
			if (handlers == null) {
				init();
			}
			if (log.isDebugEnabled()) {
				log.debug("处理类数量有: [" + handlers.size() + "]");
				for (ExceptionHandler eh : handlers) {
					log.debug(eh.toString());
				}
			}

			if (log.isDebugEnabled()) {
				log.debug("异常拦截器中catch到异常.异常为: " + e.getClass().getName());
				log.debug(MessageFormat.format("异常为:[{0}],message为:[{1}] ", e
						.getClass().getName(), e.getMessage()));
				log.debug("", e);
			}

			for (ExceptionHandler eh : handlers) {
				if (eh.isMatch(e)) {
					if (log.isDebugEnabled()) {
						log.debug(MessageFormat.format("找到匹配的异常:[{0}].准备进行处理.",
								e.getClass().getName()));
					}
					eh.handle(e);
					break;
				}
			}
		}
		if (log.isDebugEnabled()) {
			String msg = "退出异常处理拦截器.类名=[{0}],方法名=[{1}]";
			log.debug(MessageFormat.format(msg, inv.getThis().getClass()
					.getName(), inv.getMethod().getName()));
		}

		return ret;
	}

	private boolean isMatch(String methodName) {
		/**
		 * 为空的时候代表全部拦截
		 */
		if (CollectionUtils.empty(methodNames)) {
			return true;
		}

		boolean isMatch = false;
		for (String mappedName : methodNames) {
			isMatch = PatternMatchUtils.simpleMatch(mappedName, methodName);
			if (isMatch) {
				break;
			}
		}

		if (isMatch == false && log.isDebugEnabled()) {
			String msg = "methodName[{0}]没有匹配成功,将直接返回.";
			log.debug(MessageFormat.format(msg, methodName));
		}
		return isMatch;
	}

}
